
// state key to store title in
var TITLE="title";
var DEFAULT_TITLE = "New poll";
// prefix for state keys of poll options
var OPTION_KEY_PREFIX = 'option:';

function setElementText(element, text) {
  element.innerHTML = '';
  element.appendChild( document.createTextNode( text ) );
}

Array.prototype.removeItems = function(itemsToRemove) {

  if (typeof itemsToRemove == 'string') {
    itemsToRemove = [ itemsToRemove ];
  }

  var j;
  for (var i = 0; i < itemsToRemove.length; i++) {
    j = 0;
    while (j < this.length) {
      if (this[j] == itemsToRemove[i]) {
        this.splice(j, 1);
      } else {
        j++;
      }
    }
  }
}
  
/* Takes the name of a poll option and returns 
  the key to use in the Wave state. */
function convertOptionToKey(optionName) {
  return OPTION_KEY_PREFIX+optionName;
}

/*
  Takes a state key and grabs the option name
  from it. If it isn't recognised as an option
  key, null is returned.
*/
function convertKeyToOption(stateKey) {
  if (typeof stateKey != 'undefined' && stateKey && stateKey.indexOf(OPTION_KEY_PREFIX) == 0) {
    return stateKey.substring(OPTION_KEY_PREFIX.length);
  }
  return null;
}
  
  // called by Wave API after state changes
  function renderInfo(){
    var state = wave.getState();
    if(!state) return;

    var title = $.trim( state.get(TITLE) || "");
    if(title.length == 0) title = DEFAULT_TITLE;

    var titleEl = document.getElementById(TITLE);
    setElementText( titleEl, title);
    
    renderPoll(state);

    gadgets.window.adjustHeight();
  }
  
  // convenience function for creating an element with a bunch of simple attributes
  function newElement(name, attributes) {
    var el = document.createElement(name);
    for (n in attributes) {
      el[n] = attributes[n];
    }
    return el;
  }

  function renderPoll(state){
    var keys = state.getKeys();
    var pollTable = document.getElementById("pollResults");
    pollTable.innerHTML = '';
    var total = 1; // don't let total be less than 1 or we'll end up dividing by 0
    
    // loop through once building data, gathering values.
    var pollData = [];
    $(state.getKeys()).each(function(i, key) {
      wave.log("Key - " + key);
      var name = convertKeyToOption(key);
      if (name == null) {
        // key wasn't a key for an option
        return;
      }
      var data=getStateValue(key);
      if(data!=null) {
        data.key = key;
        data.name = name;
        pollData.push(data);
        
        var votes = data.participants.length;
        if (votes > total) total = votes;
      }
    });
    
    // loop through gathered data to generate view
    $(pollData).each(function(i, obj) {
      var name = obj['name'];
      
      var button = newElement("button", {className: 'voteButton'});
      if( obj.participants.indexOf( wave.getViewer().getId() ) >=0 ) {;
        button.title = 'Unvote this option';
        button.innerHTML = "-";
        $(button).bind('click', {name:name}, function(ev) { 
          removeVote(ev.data.name); 
        })
      } else {
        button.title = 'Add your vote';
        button.innerHTML = "+";
        $(button).bind('click', {name:name}, function(ev) { 
          addVote(ev.data.name); 
        });
      }
      
      var votes = obj.participants.length;
      var votesWidth = (100 * votes)/total ;
      
      var mood;
      if(votesWidth>66) mood = "high";
      else if(votesWidth>33) mood = "medium";
      else mood="low";
      
      var filled = document.createElement("div");
      filled.className = 'optionValueFill ' + mood;
      filled.style.width = votesWidth + '%';
      
      var label = document.createElement("div");
      label.className = 'optionValueText';
      if (votes > 0) {
        setElementText(label, "" + votes + " votes");
      }
      
      var votesDiv = newElement("div", { className:'votes_div' });
      filled.appendChild(label);
      votesDiv.appendChild(filled);
      
      var tr = newElement('tr', { className: 'optionRow' });
      
      var deleteLink = newElement('a', {
        innerHTML:'&times;', href:'#', className:'deleteLink', title:'Delete this option',
        onclick: function(){
          if (confirm('Really delete this option permanently?')) { removeOption(name); }
          return false;
        }
      });
      
      var td = newElement("td", { className:'optionLabel' });
      setElementText(td, name);
      td.appendChild( deleteLink );
      tr.appendChild(td);
      
      td = newElement("td", { className:'optionValue' });
      td.appendChild(votesDiv);
      tr.appendChild(td);
      
      td = newElement("td", { className:'optionButton' });
      td.appendChild(button);
      tr.appendChild(td);
      
      pollTable.appendChild(tr);
    });
  }

  function getStateValue(key){
    var value = wave.getState().get(key);
    if(value) {
      try {
        var obj = JSON.parse(value);
        if(obj.participants != null){
          return obj;
        }
      } catch(e) {
        return null;
      }
    }
    return null;
  }
  
  // TODO if the participant is already in the list, it is added again.
  // currently relies on the check to only display this function when it's
  // not present. I guess it's easy to do your own Javascript to post crap
  // into the state whatever we do here, so it's not so important.
  function addVote(option){
    var key = convertOptionToKey(option);
    var optionValue = getStateValue(key);
    if(optionValue!=null){
      optionValue.participants.push(wave.getViewer().getId());
      submitValue(key, optionValue);
    }
    gadgets.window.adjustHeight();
  }

  function removeVote(option){
    var key = convertOptionToKey(option);
    var optionValue = getStateValue(key);
    if(optionValue!=null){
      optionValue.participants.removeItems(wave.getViewer().getId());
      submitValue(key, optionValue);
    }
    gadgets.window.adjustHeight();
  }

  function setPollTitle(){
    var title = $.trim(document.getElementById('titleInput').value || "");
    if(title=="") {
      alert("Please enter a Title for the polls");
    } else {
      submitValue(TITLE, title);
    }
    showInput("set_title", false);
    gadgets.window.adjustHeight();
  }

  function addOption(){
    var option = $.trim(document.getElementById('addOptionInput').value || "");
    if(option == ""){
      alert("You cannot enter an empty option");
    } else {
      var state = wave.getState();
      var key = convertOptionToKey(option);
      if(state.get(key) != null) {
        alert("There already exists an option with that name");
      } else {
        var data = {"count":0,"participants":[]};
        submitValue(key, data);
      }
    }
    showInput("add_option", false);
    gadgets.window.adjustHeight();
  }
  
  function removeOption(optionName) {
    var key = convertOptionToKey(optionName);
    var state = wave.getState();
    var existingOption = state.get(key);
    if (existingOption) {
      submitValue(key, null);
    } else {
      alert("That key doesn't exist! " + key);
    }
  }
  
  /** save value as top level state. stringifies JSON objects. */
  function submitValue(key, value) {
    var delta = {};
    if (typeof value != 'string') {
      value = JSON.stringify(value);
    }
    delta[key] = value;
    wave.getState().submitDelta(delta);
  }

    /** 
     * Called when Gadget is loaded.
     * Registers function renderInfo which will be called
     * when ever a state is changed or a participant added
     */
  function init() {
    if (wave && wave.isInWaveContainer()) {
      wave.setStateCallback(renderInfo);
      wave.setParticipantCallback(renderInfo);
      wave.log('Starting up poll gadget');
    }
    
    showInput("set_title", false);
    showInput("add_option", false);
  }

  function setVisible(id, visible) {
    el = document.getElementById(id);
    if(el) {
      el.style.display = (visible ? "block" : "none");
    }
  }

  function showInput(name, show) {
    setVisible(name, show)
    setVisible("edit_poll", !show);
    
    gadgets.window.adjustHeight();
  }
  
  function clickSetTitle() {
    showInput("set_title", true);
    var input = document.getElementById('titleInput');
    input.value = '';
    input.focus();
  }

  function clickAddOption() {
    showInput("add_option", true);
    var input = document.getElementById('addOptionInput');
    input.value = '';
    input.focus();
  }

  gadgets.util.registerOnLoadHandler(init);
